#pragma once
#include "../source/server.hpp"
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <regex>
std::unordered_map<int, std::string> _state_msg =
    {
        {100, "Continue"},
        {101, "Switching Protocol"},
        {102, "Processing"},
        {103, "Early Hints"},
        {200, "OK"},
        {201, "Created"},
        {202, "Accepted"},
        {203, "Non-Authoritative Information"},
        {204, "No Content"},
        {205, "Reset Content"},
        {206, "Partial Content"},
        {207, "Multi-Status"},
        {208, "Already Reported"},
        {226, "IM Used"},
        {300, "Multiple Choice"},
        {301, "Moved Permanently"},
        {302, "Found"},
        {303, "See Other"},
        {304, "Not Modified"},
        {305, "Use Proxy"},
        {306, "unused"},
        {307, "Temporary Redirect"},
        {308, "Permanent Redirect"},
        {400, "Bad Request"},
        {401, "Unauthorized"},
        {402, "Payment Required"},
        {403, "Forbidden"},
        {404, "Not Found"},
        {405, "Method Not Allowed"},
        {406, "Not Acceptable"},
        {407, "Proxy Authentication Required"},
        {408, "Request Timeout"},
        {409, "Conflict"},
        {410, "Gone"},
        {411, "Length Required"},
        {412, "Precondition Failed"},
        {413, "Payload Too Large"},
        {414, "URI Too Long"},
        {415, "Unsupported Media Type"},
        {416, "Range Not Satisfiable"},
        {417, "Expectation Failed"},
        {418, "I'm a teapot"},
        {421, "Misdirected Request"},
        {422, "Unprocessable Entity"},
        {423, "Locked"},
        {424, "Failed Dependency"},
        {425, "Too Early"},
        {426, "Upgrade Required"},
        {428, "Precondition Required"},
        {429, "Too Many Requests"},
        {431, "Request Header Fields Too Large"},
        {451, "Unavailable For Legal Reasons"},
        {501, "Not Implemented"},
        {502, "Bad Gateway"},
        {503, "Service Unavailable"},
        {504, "Gateway Timeout"},
        {505, "HTTP Version Not Supported"},
        {506, "Variant Also Negotiates"},
        {507, "Insufficient Storage"},
        {508, "Loop Detected"},
        {510, "Not Extended"},
        {511, "Network Authentication Required"}};
        
std::unordered_map<std::string, std::string> _mine_msg =
    {
        {".aac", "audio/aac"},
        {".abw", "application/x-abiword"},
        {".arc", "application/x-freearc"},
        {".avi", "video/x-msvideo"},
        {".azw", "application/vnd.amazon.ebook"},
        {".bin", "application/octet-stream"},
        {".bmp", "image/bmp"},
        {".bz", "application/x-bzip"},
        {".bz2", "application/x-bzip2"},
        {".csh", "application/x-csh"},
        {".css", "text/css"},
        {".csv", "text/csv"},
        {".doc", "application/msword"},
        {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
        {".eot", "application/vnd.ms-fontobject"},
        {".epub", "application/epub+zip"},
        {".gif", "image/gif"},
        {".htm", "text/html"},
        {".html", "text/html"},
        {".ico", "image/vnd.microsoft.icon"},
        {".ics", "text/calendar"},
        {".jar", "application/java-archive"},
        {".jpeg", "image/jpeg"},
        {".jpg", "image/jpeg"},
        {".js", "text/javascript"},
        {".json", "application/json"},
        {".jsonld", "application/ld+json"},
        {".mid", "audio/midi"},
        {".midi", "audio/x-midi"},
        {".mjs", "text/javascript"},
        {".mp3", "audio/mpeg"},
        {".mpeg", "video/mpeg"},
        {".mpkg", "application/vnd.apple.installer+xml"},
        {".odp", "application/vnd.oasis.opendocument.presentation"},
        {".ods", "application/vnd.oasis.opendocument.spreadsheet"},
        {".odt", "application/vnd.oasis.opendocument.text"},
        {".oga", "audio/ogg"},
        {".ogv", "video/ogg"},
        {".ogx", "application/ogg"},
        {".otf", "font/otf"},
        {".png", "image/png"},
        {".pdf", "application/pdf"},
        {".ppt", "application/vnd.ms-powerpoint"},
        {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
        {".rar", "application/x-rar-compressed"},
        {".rtf", "application/rtf"},
        {".sh", "application/x-sh"},
        {".svg", "image/svg+xml"},
        {".swf", "application/x-shockwave-flash"},
        {".tar", "application/x-tar"},
        {".tif", "image/tiff"},
        {".tiff", "image/tiff"},
        {".ttf", "font/ttf"},
        {".txt", "text/plain"},
        {".vsd", "application/vnd.visio"},
        {".wav", "audio/wav"},
        {".weba", "audio/webm"},
        {".webm", "video/webm"},
        {".webp", "image/webp"},
        {".woff", "font/woff"},
        {".woff2", "font/woff2"},
        {".xhtml", "application/xhtml+xml"},
        {".xls", "application/vnd.ms-excel"},
        {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
        {".xml", "application/xml"},
        {".xul", "application/vnd.mozilla.xul+xml"},
        {".zip", "application/zip"},
        {".3gp", "video/3gpp"},
        {".3g2", "video/3gpp2"},
        {".7z", "application/x-7z-compressed"}};

class Util
{
public:
    /*字符串分隔函数*/
    static size_t Split(std::string src, std::string sep, std::vector<std::string> *arry)
    {
        int count = 0, offset = 0;
        // abc
        while (offset < src.size())
        {
            size_t pos = src.find(sep, offset);
            if (pos == std::string::npos) /*没有找到特定的字符*/
            {
                /*如果没有找到特定的字符， 直接将后面的字符串都加到arry里面*/
                if (offset != src.size() - 1)
                    arry->push_back(src.substr(offset));
                return arry->size();
            }

            /*如果找到了特定的字符， abc/ade/kli。就将offset到pos的位置全拿出来。 然后把offset置为pos + 1*/
            if ((pos - offset) != 0)
                arry->push_back(src.substr(offset, pos - offset));
            offset = pos + sep.size();
        }
        return arry->size();
    }

    /*读取文件内容*/
    static bool ReadFile(const std::string &filename, std::string *buf)
    {
        std::ifstream ifs(filename, std::ios::binary);
        if (ifs.is_open() == false)
        {
            ERR_LOG("open %s file failed!", filename.c_str());
            return false;
        }
        size_t size = 0;
        ifs.seekg(0, ifs.end); /*定位到if文件的末尾*/
        size = ifs.tellg();    /*获取当前指针的位置*/
        ifs.seekg(0, ifs.beg); /*定位到if文件的起始*/
        std::string str;
        str.resize(size);
        ifs.read(&str[0], size);
        if (ifs.good() == false)
        {
            ERR_LOG("read file %s faild", filename.c_str());
            ifs.close();
            return false;
        }
        *buf = str;
        return true;
    }

    /*向文件写入数据*/
    static bool WriteFile(const std::string &filename, const std::string &buf)
    {
        std::ofstream ofs(filename, std::ios::binary | std::ios::trunc);
        if (ofs.is_open() == false)
        {
            ERR_LOG("open file %s is failed", filename.c_str());
            ofs.close();
            return false;
        }

        ofs.write(buf.c_str(), buf.size());
        if (ofs.good() == false)
        {
            ERR_LOG("write %s is failed", filename.c_str());
            ofs.close();
            return false;
        }
        ofs.close();
        return true;
    }

    /*URL编码*/
    static std::string UrlEncode(const std::string url, bool convert_space_to_plus)
    {
        std::string res;
        for (auto &e : url)
        {
            if (e == '.' || e == '-' || 'e' == '~' || isalnum(e))
            {
                res += e;
                continue;
            }
            if (e == ' ' && convert_space_to_plus == true)
            {
                res += '+';
                continue;
            }

            /*剩下的字符都是需要编码成为 %HH格式*/
            char tmp[4] = {0};
            snprintf(tmp, 4, "%%%x", e);
            res += tmp;
        }
        return res;
    }

    static int HEXTOI(char c)
    {
        if (c >= '0' && c <= '9')
        {
            return c - '0';
        }
        else if (c >= 'a' && c <= 'z')
        {
            return c - 'a' + 10;
        }
        else if (c >= 'A' && c <= 'Z')
        {
            return c - 'A' + 10;
        }
        return -1;
    }

    /*URL解码*/
    static std::string UrlDecode(const std::string url, bool convert_space_to_puls)
    {
        /*遇到了%， 则将紧随其后的两个字符转化为数字， 第一个数字左移四位，然后加上第二个数字 */
        std::string res;
        for (int i = 0; i < url.size(); i++)
        {
            if (url[i] == '+' && convert_space_to_puls == true)
            {
                res += ' ';
                continue;
            }
            if (url[i] == '%' && i + 2 < url.size())
            {
                char v1 = HEXTOI(url[i + 1]);
                char v2 = HEXTOI(url[i + 2]);
                char v = (v1 << 4) + v2;
                res += v;
                i += 2;
                continue;
            }
            res += url[i];
        }
        return res;
    }

    /*响应状态码的描述信息获取*/
    static std::string StateDesc(int state)
    {
        auto it = _state_msg.find(state);
        if (it != _state_msg.end())
        {
            return it->second;
        }
        return "Unknown";
    }

    /*根据文件名后缀获取文件mine*/
    static std::string ExtMine(std::string filename)
    {
        /*先获取扩展名*/

        size_t pos = filename.find_last_of('.');
        if (pos == std::string::npos)
        {
            return "application/octet-stream";
        }

        /*根据扩展名获取mine*/
        std::string ext = filename.substr(pos);
        auto it = _mine_msg.find(ext);
        if (it == _mine_msg.end())
        {
            return "application/octet-stream";
        }
        return it->second;
    }

    /*判断一个文件是否是一个目录*/
    static bool IsDirectory(const std::string filename)
    {
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret < 0)
        {
            return false;
        }
        return S_ISDIR(st.st_mode);
    }

    /*判断一个文件是否是一个普通文件*/
    static bool IsRegular(const std::string filename)
    {
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret < 0)
        {
            return false;
        }
        return S_ISREG(st.st_mode);
    }

    /*http请求的资源路径有效性判断*/
    static bool VaidPath(const std::string &path)
    {
        std::vector<std::string> subdir;
        Split(path, "/", &subdir);
        int level = 0;
        for (auto &dir : subdir)
        {
            if (dir == "..")
            {
                level--;
                if (level < 0)
                    return false;
                continue;
            }
            level++;
        }
        return true;
    }
};

class HttpRequest
{
public:
    std::string _method;                                   /*请求方法*/
    std::string _path;                                     /*资源路径*/
    std::string _version;                                  /*协议版本*/
    std::string _body;                                     /*请求正文*/
    std::smatch _matches;                                  /*资源路径的正则提取数据*/
    std::unordered_map<std::string, std::string> _headers; /*头部字段*/
    std::unordered_map<std::string, std::string> _params;  /*查询字符串*/

public:
    void ReSet()
    {
        _method.clear();
        _path.clear();
        _version.clear();
        _body.clear();
        std::smatch matches;
        matches.swap(_matches);
        _headers.clear();
        _params.clear();
    }
    void SetHeader(std::string &key, std::string &val) /*插入头部字段*/
    {
        _headers.insert({key, val});
    }
    bool HasHeader(const std::string &key) /*判断是否有某个指定的头部字段*/
    {
        auto it = _headers.find(key);
        if (it == _headers.end())
        {
            return false;
        }
        return true;
    }
    std::string GetHeader(const std::string &key) /*获取指定头部字段的值*/
    {
        if (HasHeader(key) == false)
        {
            return "";
        }
        return _headers[key];
    }
    void SetParam(std::string &key, std::string &val) /*插入查询字符串*/
    {
        _params.insert({key, val});
    }
    bool HasParam(const std::string &key) /*判断是否有某个指定的查询字符串*/
    {
        auto it = _params.find(key);
        if (it == _params.end())
        {
            return false;
        }
        return true;
    }
    std::string GetParam(const std::string &key) /*获取指定的查询字符串*/
    {
        if (HasParam(key) == false)
        {
            return "";
        }
        return _params[key];
    }
    size_t ContentLength() /*获取正文长度*/
    {
        bool ret = HasHeader("Content-Length");
        if (ret == false)
        {
            return 0;
        }
        std::string clen = GetHeader("Content-Length");
        return std::stol(clen);
    }
    bool Close() /*判断是否是短链接*/
    {
        /*没有Connection字段，或者有Connection但是值是close， 则都是短链接， 否则就是长链接*/
        if (HasHeader("Connection") == true && GetHeader("Connection") == "keep-alive")
        {
            return false;
        }
        return true;
    }
};

class HttpResponse
{
private:
    int _state;
    bool _redirect_flag;
    std::string _body;
    std::string _redirect_url;
    std::unordered_map<std::string, std::string> _headers;

public:
    HttpResponse(int state = 200)
        : _redirect_flag(false),
          _state(state)
    {
    }

    int &GetState()
    {
        return _state;
    }
    std::string &GetBody()
    {
        return _body;
    }
    bool &GetRedirectFlag()
    {
        return _redirect_flag;
    }
    std::string &GetRedirectUrl()
    {
        return _redirect_url;
    }

    std::unordered_map<std::string, std::string> &GetHeaders()
    {
        return _headers;
    }

    void ReSet()
    {
        _state = 200;
        _redirect_flag = false;
        _body.clear();
        _redirect_url.clear();
        _headers.clear();
    }

    void SetHeader(const std::string &key, const std::string &val) /*插入头部字段*/
    {
        _headers.insert({key, val});
    }
    bool HasHeader(const std::string &key) /*判断是否有某个指定的头部字段*/
    {
        auto it = _headers.find(key);
        if (it == _headers.end())
        {
            return false;
        }
        return true;
    }
    std::string GetHeader(const std::string &key) /*获取指定头部字段的值*/
    {
        if (HasHeader(key) == false)
        {
            return "";
        }
        return _headers[key];
    }

    void SetContent(const std::string &body, const std::string &type = "text/html")
    {
        _body = body;
        std::string str("Content-type");
        SetHeader(str, type);
    }
    void SetRedirect(const std::string &url, int state = 302) /*默认是302*/
    {
        _state = state;
        _redirect_flag = true;
        _redirect_url = url;
    }
    bool Close()
    {
        /*没有Connection字段，或者有Connection但是值是close， 则都是短链接， 否则就是长链接*/
        if (HasHeader("Connection") == true && GetHeader("Connection") == "keep-alive")
        {
            return false;
        }
        return true;
    }
};

typedef enum
{
    RECV_HTTP_ERROR,
    RECV_HTTP_LINE,
    RECV_HTTP_HEAD,
    RECV_HTTP_BODY,
    RECV_HTTP_OVER
} HttpRecvState;
#define MAX_LINE 8192
class HttpContent
{
private:
    int _resp_state;           /*响应状态码*/
    HttpRecvState _recv_state; /*当前接收及解析的阶段状态*/
    HttpRequest _request;      /*已经解析得到的请求信息*/

private:
    /*获取一行数据*/
    bool RecvHttpLine(Buffer *buf)
    {
        if (_recv_state != RECV_HTTP_LINE)
            return false;
        /*1、获取一行数据*/
        /*这里需要判断两种条件， 一种是缓冲区里面的数据不足一行， 另一种情况就是一行的数据超大*/
        std::string line = buf->GetLineAndPop();
        if (line.size() == 0)
        {
            /*缓冲区中的数据不足一行， 则需要判断缓冲区的可读数据长度，
            如果缓冲区里面的数据一行太长， 就不合适。*/
            if (buf->ReadAbleSize() > MAX_LINE)
            {
                _recv_state = RECV_HTTP_ERROR;
                _resp_state = 414; /*URI TOO LONG*/
                return false;
            }
            /*不足以行， 但是也不多， 直接退出就行了*/
            return true;
        }

        if (line.size() > MAX_LINE)
        {
            _recv_state = RECV_HTTP_ERROR;
            _resp_state = 414;
            return false;
        }
        bool ret = ParseHttpLine(line);
        if (ret == false)
        {
            return false;
        }
        _recv_state = RECV_HTTP_HEAD;
        return true;
    }
    bool ParseHttpLine(const std::string &line)
    {
        std::smatch matches;
        std::regex e("(GET|PUT|DELETE|HEAD|POST) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?");
        bool ret = std::regex_match(line, matches, e);
        if (ret == false)
        {
            _recv_state = RECV_HTTP_ERROR;
            _resp_state = 400; /*BAD REQUEST*/
            return false;
        }
        /*请求方法的获取*/
        _request._method = matches[1];
        /*资源路径的获取， 这里面需要进行解码操作， 但是不需要加号转空格*/
        _request._path = Util::UrlDecode(matches[2], false);
        /*协议版本的获取*/
        _request._version = matches[4];
        /*查询字符串的获取与处理*/
        std::vector<std::string> query_string_arry;
        std::string query_string = matches[3];
        /*查询字符串的格式 key == val & key == val。先以&进行分隔，
        根据各个字串，以=进行分割, 得到key和value。得到之后也需要进行url解码*/
        Util::Split(query_string, "&", &query_string_arry);
        for (auto &str : query_string_arry)
        {
            size_t pos = str.find("=");
            if (pos == std::string::npos)
            {
                DBG_LOG("into find = Line");
                _recv_state = RECV_HTTP_ERROR;
                _resp_state = 400;
                return false;
            }

            std::string key = Util::UrlDecode(str.substr(0, pos), true);
            std::string val = Util::UrlDecode(str.substr(pos + 1), true); /*在w3c标准中，空格要被转化为加号*/
            _request.SetParam(key, val);
        }
        return true;
    }

    bool RecvHttpHead(Buffer *buf)
    {
        if (RECV_HTTP_HEAD != _recv_state)
            return false;
        while (1)
        {

            /*一行一行的取出数据。 直到遇到空行*/
            /*1、获取一行数据*/
            std::string line = buf->GetLineAndPop();
            if (line.size() == 0)
            {
                if (buf->ReadAbleSize() > MAX_LINE)
                {
                    _recv_state = RECV_HTTP_ERROR;
                    _resp_state = 414; /*URI TOO LONG*/
                    return false;
                }
                return true;
            }
            if (line.size() > MAX_LINE)
            {
                _recv_state = RECV_HTTP_ERROR;
                _resp_state = 414;
                return false;
            }
            if (line == "\n" || line == "\r\n")
            {
                break;
            }
            bool ret = ParseHttpHeader(line);
            if (ret == false)
            {
                return false;
            }
        }
        _recv_state = RECV_HTTP_BODY;
        return true;
    }
    bool ParseHttpHeader(std::string &line)
    {
        if (line.back() == '\n')
            line.pop_back();
        if (line.back() == '\r')
            line.pop_back();
        size_t pos = line.find(": ");
        if (pos == std::string::npos)
        {
            _recv_state = RECV_HTTP_ERROR;
            DBG_LOG("into find : Header");
            _resp_state = 400;
            return false;
        }
        std::string key = line.substr(0, pos);
        std::string val = line.substr(pos + 2);
        _request.SetHeader(key, val);

        return true;
    }

    bool RecvHttpBody(Buffer *buf)
    {
        if (_recv_state != RECV_HTTP_BODY)
            return false;
        /*1、获取正文长度*/
        size_t content_length = _request.ContentLength();
        if (content_length == 0)
        {
            /*没有正文，则请求接收解析完毕*/
            _recv_state = RECV_HTTP_OVER;
            return true;
        }
        /*2、当前已经接收了多少正文， 其实就是往_request._body中放了多少数据了*/
        size_t real_len = content_length - _request._body.size(); /*实际还需要接收的正文长度*/
        /*3、接收正文放到body中， 但是也要考虑当前缓冲区中的数据， 是否是全部的正文*/
        /*3.1、缓冲区中的数据， 包含了当前请求的所有正文，则取出所需的数据。*/
        if (buf->ReadAbleSize() >= real_len)
        {
            _request._body.append(buf->ReadPosition(), real_len);
            buf->MoveReadOffset(real_len);
            _recv_state = RECV_HTTP_OVER;
            return true;
        }
        /*3.2、缓冲区中数据， 无法满足当前正文的需要，数据不足，取出数据， 然后等待数据到来*/
        _request._body.append(buf->ReadPosition(), buf->ReadAbleSize());
        buf->MoveReadOffset(buf->ReadAbleSize());
        return true;
    }

public:
    HttpContent()
        : _resp_state(200),
          _recv_state(RECV_HTTP_LINE)
    {
    }
    int RespState() /*当前响应的响应状态码*/
    {
        return _resp_state;
    }
    HttpRecvState RecvState() /*当前接收以及解析的阶段*/
    {
        return _recv_state;
    }
    HttpRequest &Request() /*获取已经解析得到的请求信息*/
    {
        return _request;
    }
    /*接收并解析HTTP请求*/
    void RecvHttpRequest(Buffer *buf)
    {

        switch (_recv_state)
        {
        case RECV_HTTP_LINE:
            RecvHttpLine(buf);
        case RECV_HTTP_HEAD:
            RecvHttpHead(buf);
        case RECV_HTTP_BODY:
            RecvHttpBody(buf);
        }

        return;
    }

    void ReSet()
    {
        _resp_state = 200;
        _recv_state = RECV_HTTP_LINE;
        _request.ReSet();
    }
};

class HttpServer
{
private:
    using Handler = std::function<void(const HttpRequest &, HttpResponse *)>; /*包装函数*/
    using Handlers = std::vector<std::pair<std::regex, Handler>>;
    Handlers _get_route;    /**/
    Handlers _post_route;   /**/
    Handlers _put_route;    /**/
    Handlers _delete_route; /**/
    std::string _basedir;   /*静态资源根目录*/
    TcpServer _server;      /**/
private:
    void ErrorHandler(HttpResponse *rsp)
    {
        /*组织一个错误的展示页面*/
        std::string body;
        body += "<html>";
        body += "<head>";
        body += "<meta content='text/html; charset=utf-8' http-equiv='content-type' />";
        body += "</head>";
        body += "<body>";
        body += "<h1>";
        body += std::to_string(rsp->GetState());
        body += " ";
        body += Util::StateDesc(rsp->GetState());
        body += "</h1>";
        body += "</body>";
        body += "</html>";
        /*2、将页面数据，当作响应正文，放入rsp中*/
        rsp->SetContent(body, "text/html");
    }
    void WriteResponse(const PtrConn &conn, HttpRequest &req, HttpResponse &resp) /*将http中的 Response要素按照http协议的格式进行组织 + 发送*/
    {
        /*先完善头部字段，将rsp中的要素，按照http协议格式进行组织， 发送数据*/
        if (req.Close() == true)
        {
            resp.SetHeader("Connection", "close");
        }
        else
        {
            resp.SetHeader("Connection", "keep-alive");
        }
        if (resp.GetBody().empty() == false && resp.HasHeader("Content-Length") == false)
        {
            resp.SetHeader("Connect-Length", std::to_string(resp.GetBody().size()));
        }
        if (resp.GetBody().empty() == false && resp.HasHeader("Content-Type") == false)
        {
            resp.SetHeader("Content-Type", "application/octet-stream");
        }
        if (resp.GetRedirectFlag() == true)
        {
            resp.SetHeader("Location", resp.GetRedirectUrl());
        }
        
        /*将resp中的要素按照http协议格式进行组织*/
        std::stringstream rsp_str;
        rsp_str << req._version << " " << std::to_string(resp.GetState()) << " " << Util::StateDesc(resp.GetState()) << "\r\n";
        for (auto &head : resp.GetHeaders())
        {
            rsp_str << head.first << ": " << head.second << "\r\n";
        }
        rsp_str << "\r\n";
        rsp_str << resp.GetBody();
        /*发送数据*/
        conn->Send((char *)rsp_str.str().c_str(), rsp_str.str().size());
    }
    bool IsFileHandler(HttpRequest &req) /*判断是否是静态资源请求*/
    {
        /*1、必须设置了静态资源根目录*/
        if (_basedir.empty())
            return false; /*_根目录为空的话就返回false, 没有根目录*/

        /*2、请求方法， 必须是GET / HEAD请求方法*/
        if (req._method != "GET" && req._method != "HEAD")
            return false; /*请求方法必须是GET或者HEAD, 两个都不是， 那么直接返回false*/

        /*3、请求的资源路径必须是一个合法路径*/
        if (Util::VaidPath(req._path) == false)
            return false; /*请求的资源路径不合法， 就返回false*/
        /*4、请求的资源必须存在*/
        std::string req_path = _basedir + req._path; /*创建临时对象是为了避免直接修改请求的资源路径， 因此定义一个临时对象*/
        if (req_path.back() == '/')                  /*最后一个字符是/， 说明没有指定当前目录下的某个文件， 就默认访问index.html*/
        {
            req_path += "index.html";
        }

        /*代码走到这，既是获取资源， 又是有资源， 而且有静态资源根目录。
          说明是一个合法请求， 就要判断是不是普通文件， 如果不是普通文件， 直接返回false*/
        if (Util::IsRegular(req_path) == false)
            return false;

        /*走到这， 说明req_path路径就是一个普通文件, 那么就是静态资源的请求， */
        req._path = req_path;
        return true;
    }
    bool FileHandler(const HttpRequest &req, HttpResponse *resp) /*静态资源的请求处理*/
    {
        bool ret = Util::ReadFile(req._path, &resp->GetBody());
        if (ret == false)
            return false;

        std::string mine = Util::ExtMine(req._path);
        resp->SetHeader("Content-Type", mine);
        return true;
    }
    void Dispatcher(HttpRequest &req, HttpResponse *resp, Handlers handlers) /*功能性请求分类*/
    {
        /*在对方请求方法的路由表中， 查找是否含有对应资源请求的处理函数， 有则调用， 没有则返回404
          思想就是路由表存储的是键值对 -- 正则表达式 & 处理函数
          使用正则表达式， 对请求的资源路径进行正则匹配， 匹配成功就是用对应函数进行处理
          /numbers/\d+      /numbers/12345
        */
        for (auto &handler : handlers)
        {
            std::regex re(handler.first);
            Handler &functor = handler.second;
            bool ret = std::regex_match(req._path, req._matches, re);
            if (ret == false)
            {
                continue;
            }
            functor(req, resp);
            return;
        }
        DBG_LOG("yes, i come here");
        resp->GetState() = 404;
    }
    void Route(HttpRequest &req, HttpResponse *resp) /**/
    {
        /*1、对请求进行分辨， 是一个静态资源请求， 还是一个功能性请求*/
        /*静态资源请求， 就需要进行静态资源的处理
          功能性请求， 就需要通过几个请求路由表来确定是否有处理函数。
          既不是静态资源请求， 也没有设置对应的功能性请求处理函数， 就返回404.*/
        if (IsFileHandler(req) == true)
        {
            /*是一个静态资源请求， 那么就进行静态资源的处理*/
            FileHandler(req, resp);
            return;
        }
        if (req._method == "GET" || req._method == "HEAD")
        {
            return Dispatcher(req, resp, _get_route);
        }
        else if (req._method == "POST")
        {
            return Dispatcher(req, resp, _post_route);
        }
        else if (req._method == "PUT")
        {
            return Dispatcher(req, resp, _put_route);
        }
        else if (req._method == "DELETE")
        {
            return Dispatcher(req, resp, _delete_route);
        }
        resp->GetState() = 405; /*page not found*/
    }

    void OnConnected(const PtrConn &conn) /*设置上下文*/
    {
        conn->SetContext(HttpContent());
        DBG_LOG("NEW CONNECTION %p", conn.get());
    }
    void OnMessage(const PtrConn &conn, Buffer *buf) /*缓冲区数据解析 + 处理*/
    {
        while (buf->ReadAbleSize() > 0)
        {
            /*获取上下文*/
            HttpContent *context = std::any_cast<HttpContent>(&conn->GetContext());

            /*通过上下文对缓冲区数据进行解析， 得到HttpRequest对象*/
            /*如果缓冲区的数据解析出错， 就直接回复出错响应
              如果解析正常，且请求已经获取完毕， 才进行处理。*/

            context->RecvHttpRequest(buf);
            HttpRequest &req = context->Request();
            HttpResponse rsp(context->RespState());
            if (context->RespState() >= 400)
            {
                /*进行错误响应，关闭链接*/ /*添加一个错误显示页面到rsp中*/
                ErrorHandler(&rsp);
                WriteResponse(conn, req, rsp); /*组织响应发送给客户端*/
                context->ReSet();
                buf->MoveReadOffset(buf->ReadAbleSize());   
                conn->Shutdown();              /*关闭连接*/
                return;
            }

            if (context->RecvState() != RECV_HTTP_OVER)
            {
                /*当前请求还没有接受完整，则退出，等新数据到来再重新继续处理*/
                return;
            }
            /*请求路由 + 业务处理*/
            Route(req, &rsp);
            /*4、对HttpResponse进行组织发送*/
            WriteResponse(conn, req, rsp);

            /*5、重置上下文*/
            (*context).ReSet();

            /*6、根据长短连接判断是否关闭连接或者继续处理*/
            if (rsp.Close() == true)
                conn->Shutdown(); /*短链接则直接关闭*/
        }
        return;
    }

public:
    HttpServer(int port, int timeout = 100)
        : _server(port)
    {
        _server.EnableInactiveRelease(timeout);
        /*OnConnection， 给链接设置上下文。*/
        _server.SetConnectedCallback(std::bind(&HttpServer::OnConnected, this, std::placeholders::_1));
        /*给服务器设置一旦来了消息的业务处理*/
        _server.SetMessageCallback(std::bind(&HttpServer::OnMessage, this, std::placeholders::_1, std::placeholders::_2));
    }
    void SetBaseDir(const std::string &path)
    {
        if (Util::IsDirectory(path) == false)
        {
            ERR_LOG("cannot find target directory");
            abort();
        }
        _basedir = path;
    }
    /*获取请求， 这个pattern就是正则表达式。设置/添加请求（请求的正则表达式）与处理函数的映射关系*/
    void get(const std::string &pattern, const Handler &handler) /*第一个参数是正则表达式*/
    {
        _get_route.push_back({std::regex(pattern), handler});
    }
    void Post(const std::string &pattern, const Handler &handler)
    {
        _post_route.push_back({std::regex(pattern), handler});
    }
    void Put(const std::string &pattern, const Handler &handler)
    {
        _put_route.push_back({std::regex(pattern), handler});   //将pattern初始化一个regex， 
    }
    void Delete(const std::string &pattern, const Handler &handler)
    {
        _delete_route.push_back({std::regex(pattern), handler});
    }
    void SetThreadCount(int count)
    {
        _server.SetPoolCapacity(count);
    }
    void Listen()
    {
        _server.Start();
    }
};
